/** @file
@brief C++ Function Implementations

C++ support is built out of inline functions in the structures. Sometimes these functions need to reference functions and types that aren't yet defined. When this happens, the function body in the structure is implemented here; as this file is included last in pryn.h, all symbols in Pryn are visible from this point.
*/
#ifndef PRYN_CPP_H
#define PRYN_CPP_H

#if __cplusplus && !__DOXYGEN__
// Global
	struct PrynWrapperBase
	{
		PrynState *state;
		void *function; ///< Function pointer.
		void *data; ///< Data pointer.
		void (*destructor) (void *data); ///< Destroys data pointer or 0 for none.
	};

	inline void PrynWrapperDelete (void *data)
	{
		PrynWrapperBase *wrapper = (PrynWrapperBase *) data;
		if (wrapper->destructor) wrapper->destructor (wrapper->data);
		wrapper->state->free (data);
	}

	inline PrynResult prynThrow (PrynState *state, PrynResult result)
	{
		if (result < 0)
			throw PrynException (state, result);
		return result;
	}

// PrynFactory
	inline PrynComponent *PrynFactory::createComponent () { return PrynComponent::Create (this); }
	inline PrynComponent *PrynFactory::allocateComponent (size_t proprietarySize) { return PrynComponent::Allocate (this, proprietarySize); }

	PrynReturnCallbackWrapperBody (Factory, CreateFunction, createFunction, this->state (), (PrynFactory *factory, PrynComponent **output, void *data), (factory, data), (PrynFactory *factory, void *data), PrynComponent *, output)
	PrynReturnCallbackWrapperBody (Factory, DisplayNameFunction, displayNameFunction, this->state (), (PrynComponent *component, PrynString *value, void *data), (component, data), (PrynComponent *component, void *data), PrynString, value)
	PrynCallbackWrapperBody (Factory, ClickFunction, clickFunction, this->state (), (PrynComponent *component, void *data), (component, data))
	PrynCallbackWrapperBody (Factory, PinConnectedFunction, pinConnectedFunction, this->state (), (PrynPin *pin, void *data), (pin, data))
	PrynCallbackWrapperBody (Factory, PinDisconnectedFunction, pinDisconnectedFunction, this->state (), (PrynPin *pin, void *data), (pin, data))
	PrynCallbackWrapperBody (Factory, PinChangeValueFunction, pinChangeValueFunction, this->state (), (PrynPin *pin, void *data), (pin, data))

// PrynFactoryClass
	void PrynFactoryClass::construct (PrynLibrary *library)
	{
		pBase = library->createFactory (id ());
		name (defaultName ());
		description (defaultDescription ());
		pBase->createFunction (&createFunctionStatic, this, 0);
		pBase->pinChangeValueFunction (&pinChangeValueFunctionStatic, this, 0);
		pBase->pinConnectedFunction (&pinConnectedFunctionStatic, this, 0);
		pBase->displayNameFunction (&displayNameFunctionStatic, this, 0);
		pBase->clickFunction (&clickFunctionStatic, this, 0);
	}

// PrynLibrary
	inline PrynFactory *PrynLibrary::createFactory (const PrynString &id) { return PrynFactory::Create (this, id); }
	inline PrynType *PrynLibrary::createType (const PrynString &id) { return PrynType::Create (this, id); }

// PrynMediator
	inline PrynMediator *PrynMediator::Create (PrynLibrary *library, const PrynString &id) { PrynMediator *result; library->checkError (prynMediatorCreate (&result, library, &id)); return result; }

// PrynPin
	inline PrynPin *PrynPin::Create (PrynComponent *component, PrynPinDirection direction, const PrynString &id, const PrynString &name, const PrynString &description) { PrynPin *pin; component->checkError (prynPinCreate (&pin, component, direction, &id, &name, &description)); return pin; }
	inline PrynPin *PrynPin::CreateOutput (PrynComponent *component, const PrynString &id, const PrynString &name, const PrynString &description) { PrynPin *pin; component->checkError (prynPinCreateOutput (&pin, component, &id, &name, &description)); return pin; }
	inline PrynPin *PrynPin::CreateInput (PrynComponent *component, const PrynString &id, const PrynString &name, const PrynString &description) { PrynPin *pin; component->checkError (prynPinCreateInput (&pin, component, &id, &name, &description)); return pin; }

// PrynState
	inline void PrynState::free (void *pointer) { try { prynFree (this, pointer); } catch (PrynException &exception) { exception; } }

// PrynString
	inline PrynString PrynString::Allocate (PrynState *state, size_t length) { PrynString result; state->checkError (prynStringAllocate (&result, state, length)); return result; }
	inline const char *PrynString::toZ (PrynState *state) const { const char *result; state->checkError (prynStringToZ (this, state, &result)); return result; }
	inline void PrynString::freeZ (PrynState *state, const char *zstring) const { if (zstring != pointer) state->free ((void *) zstring); }
	inline PrynString PrynString::duplicate (PrynState *state) const { PrynString result; state->checkError (prynStringDuplicate (&result, state, this)); return result; }
	inline PrynString PrynString::join (PrynState *state, PrynString &other) const { PrynString result; state->checkError (prynStringJoin (&result, state, this, &other)); return result; }
	inline PrynString::PrynString (const char *text) { prynStringFromZ (this, text); }
	inline PrynString PrynString::FromZMaximum (const char *pointer, size_t maximumLength) { PrynString result; prynCheckErrorNull (prynStringFromZMaximum (&result, pointer, maximumLength)); return result; }
	inline void PrynString::free (PrynState *state) { prynStringFree (this, state); }
	inline bool PrynString::operator == (const PrynString &other) const { return PrynIsTrue (prynCheckErrorNull (prynStringEqual (this, &other))); }
	inline bool PrynString::operator == (const char *other) const { return *this == PrynString (other); }
	inline bool PrynString::operator != (const PrynString &other) const { return !(*this == other); }
	inline bool PrynString::operator != (const char *other) const { return !(*this == other); }
	inline bool PrynString::startsWith (const PrynString &other) const { return PrynIsTrue (prynCheckErrorNull (prynStringStartsWith (this, &other))); }
	inline void PrynString::overwrite (PrynState *state, const PrynString &overwrite) { prynCheckErrorNull (prynStringOverwrite (this, state, &overwrite)); }

	inline PrynString PrynString::sliceToEnd (size_t offset) const { PrynString result; prynCheckErrorNull (prynStringSliceToEnd (&result, this, offset)); return result; }
	inline PrynString PrynString::sliceTo (size_t end) const { PrynString result; prynCheckErrorNull (prynStringSliceTo (&result, this, end)); return result; }

// PrynTag
	inline PrynTag *PrynTag::Create (PrynObject object, const PrynString &id, void *data) { PrynTag *result; object.checkError (prynTagCreate (&result, &object, &id, data)); return result; }

// PrynType
	inline PrynType *PrynType::Create (PrynLibrary *library, const PrynString &id) { PrynType *result; library->checkError (prynTypeCreate (&result, library, &id)); return result; }
	inline PrynType *PrynType::Find (PrynState *state, const PrynString &id) { PrynType *result; state->checkError (prynTypeFind (&result, state, &id)); return result; }
	
	PrynCallbackWrapperBody (Type, CreateFunction, createFunction, this->state (), (PrynValue **value, PrynType *type, void *initial, void *data), (value, type, initial, wrapper->data))

	PrynCallbackWrapperBody (Type, ConnectionImageFunction, connectionImageFunction, this->state (), (PrynValue *value, int width, int height, PrynColor *image, PrynColor *fallback, void *data), (value, width, height, image, fallback, data))

	PrynCallbackWrapperBody (Type, ColorsFunction, colorsFunction, this->state (), (PrynValue *value, PrynColor *outer, PrynColor *inner, void *data), (value, outer, inner, data))

	PrynCallbackWrapperBody (Type, DestroyFunction, destroyFunction, this->state (), (PrynValue *value, void *data), (value, data))

// PrynTypeClass
	inline void PrynTypeClass::construct (PrynLibrary *library)
	{
		pBase = library->createType (id ());
		name (defaultName ());
		description (defaultDescription ());
		pBase->createFunction (&createFunctionStatic, this, 0);
		pBase->destroyFunction (&destroyFunctionStatic, this, 0);
		pBase->colorsFunction (&colorsFunctionStatic, this, 0);
		pBase->connectionImageFunction (&connectionImageFunctionStatic, this, 0);
	}

	inline PrynValue *PrynTypeClass::allocateValue (size_t length, void *initial) { return PrynValue::Allocate (pBase, length, initial); }

	inline PrynValue *PrynTypeClass::createFunction (void *initial)
	{
		throw PrynException (state (), PrynResultUnimplemented);
		return 0;
	}

	inline void PrynTypeClass::createFunctionStatic (PrynValue **value, PrynType *type, void *initial, void *data)
	{
		PrynTypeClass *self = (PrynTypeClass *) data;
		*value = self->createFunction (initial);
	}

// PrynValue
	inline PrynValue *PrynValue::Create (PrynState *state, const PrynString &id, void *initial) { PrynValue *output; state->checkError (prynValueCreateFromId (&output, state, &id, initial)); return output; }
#endif /* __cplusplus */

#endif /* PRYN_CPP_H */